# No Limit on Terms Served? Explaining the Tenure of Incumbent Governors 
# in Russia during Medvedev's Presidency

# forthcoming in Communist and Post-Communist Studies

# by Ekaterina Paustyan


# Remove everything from the working environment:
rm(list=ls())

# Set your working directory: 
setwd()
getwd()

# Load the packages:
library(QCA)
library(SetMethods)

# Load raw data:
DT <- read.csv("raw_data.csv", row.names = 1, sep=",")
head(DT)


# Direct calibration ---- 

#VOT#

# Check the distribution of the raw data
hist(DT$VOT_raw_1,
     xlab = "VOT_raw",
     main = paste("Histogram of the raw VOT scores"))

# Calibrate the result of the 2007 Duma elections

VOT <- calibrate(DT$VOT_raw_1, 
                 type = "fuzzy", 
                 thresholds = "i=65, c=51, e=48",
                 logistic = TRUE, idm = 0.95)
VOT

# To add the new calibrated set to the data frame:
DT$VOT<-VOT
head(DT)


# Plot the raw data against the fuzzy set scores:
plot(DT$VOT_raw_1, DT$VOT,
     main = "Calibration of VOT" ,
     xlab = "Raw score" ,
     ylab = "Calibrated score",
     abline (h = 0.5 ,
             v = 51)) 

# Calibrate separately the result of the 2011 Duma elections

VOT2 <- calibrate(DT$VOT_raw_2,
                  type = "fuzzy",
                  thresholds = c(29, 40, 49),
                  logistic = TRUE, idm = 0.95)
VOT2


# To add the new calibrated set to the data frame:
DT$VOT2<-VOT2
head(DT)


# Replace the data in VOT using fs membership scores from VOT2 
# for the following cases:

# Tkachev_KDA

DT[8, 1-9]
DT[8, 8] = 0.9949516


# Polezhaev_OMS
DT[4, 1-9]
DT[4, 8] = 0.4739252

# Kress_TOM
DT[3, 1-9]
DT[3, 8] = 0.3392779

# Gromov_MOS
DT[1, 1-9]
DT[1, 8] = 0.1279465

# Pozgalev_VLG 
DT[2, 1-9]
DT[2, 8] = 0.1459578

head(DT)

# Remove column VOT2
DT <- DT[, -9]
head(DT)

# Visualize the the fuzzy set scores using a histogram:
hist(DT$VOT,
     xlab = "VOT",
     main = paste("Histogram of the fuzzy set VOT scores"))


# STAB #

# Check the distribution of the raw data
hist(DT$STAB_raw,
     xlab = "STAB_raw",
     main = paste("Histogram of the raw STAB scores"))


STAB <- calibrate(DT$STAB_raw,
                  type = "fuzzy",
                  thresholds = c(2, 1.5, 1),
                  logistic = TRUE, idm = 0.95)



STAB 

# To add the new calibrated set to the data frame:
DT$STAB<-STAB
head(DT)

# Visualize the the fuzzy set scores using a histogram:
hist(DT$STAB,
     xlab = "STAB",
     main = paste("Histogram of the fuzzy set STAB scores"))

# Plot the raw data against the fuzzy set scores:
plot(DT$STAB_raw, DT$STAB,
     main = "Calibration of STAB" ,
     xlab = "Raw score" ,
     ylab = "Calibrated score",
     abline (h = 0.5 ,
             v = 1.5))


# EFF #

# Check the distribution of the raw data
hist(DT$EFF_raw,
     xlab = "EFF",
     main = paste("Histogram of the raw EFF scores"))



EFF <- calibrate(DT$EFF_raw,
                 type = "fuzzy",
                 thresholds = c(60, 40, 20),
                 logistic = TRUE, idm = 0.95)
EFF

# To add the new calibrated set to the data frame:
DT$EFF <-EFF
head(DT)



# Visualize the the fuzzy set scores using a histogram:
hist(DT$EFF,
     xlab = "EFF",
     main = paste("Histogram of the fuzzy set EFF scores"))


# Plot the raw data against the fuzzy set scores:
plot(DT$EFF_raw, DT$EFF,
     main = "Calibration of EFF" ,
     xlab = "Raw score" ,
     ylab = "Calibrated score",
     abline (h = 0.5 ,
             v = 40))


# POPUL # 

# Check the distribution of the raw data
hist(DT$POPUL_raw,
     xlab = "POPUL_raw",
     main = paste("Histogram of the raw POPUL scores"))

POPUL <- calibrate(DT$POPUL_raw,
                   type = "fuzzy",
                   thresholds = c(30, 40, 60),
                   logistic = TRUE)
POPUL

# To add the new calibrated set to the data frame:
DT$POPUL<-POPUL
head(DT)

# Visualize the the fuzzy set scores using a histogram:
hist(DT$POPUL,
     xlab = "POPUL",
     main = paste("Histogram of the fuzzy set POPUL scores"))

# Plot the raw data against the fuzzy set scores:
plot(DT$POPUL_raw, DT$POPUL,
     main = "Calibration of POPUL" ,
     xlab = "Raw score" ,
     ylab = "Calibrated score",
     abline (h = 0.5 ,
             v = 40))


# ECON # 

# Check the distribution of the raw data
hist(DT$ECON_raw,
     xlab = "ECON_raw",
     main = paste("Histogram of the raw ECON scores"))

ECON <- calibrate(DT$ECON_raw,
                 type = "fuzzy",
                 thresholds = c(0, 2.5, 4),
                 logistic = TRUE)
ECON


# To add the new calibrated set to the data frame:
DT$ECON<-ECON
head(DT)

# Visualize the the fuzzy set scores using a histogram:
hist(DT$ECON,
     xlab = "ECON",
     main = paste("Histogram of the fuzzy set ECON scores"))

# Plot the raw data against the fuzzy set scores:
plot(DT$ECON_raw, DT$ECON,
     main = "Calibration of ECON" ,
     xlab = "Raw score" ,
     ylab = "Calibrated score",
     abline (h = 0.5 ,
             v = 2.5))


# OUT # 

# Check the distribution of the raw data
hist(DT$OUT,
     xlab = "OUT",
     main = paste("Histogram of the raw OUT scores"))

OUT <- calibrate(DT$OUT,
                 type = "fuzzy",
                 thresholds = c(0, 0.2, 1),
                 logistic = TRUE) 



OUT


# To add the new calibrated set to the data frame:
DT$OUT <-OUT
head(DT)


# Visualize the the fuzzy set scores using a histogram:
hist(DT$OUT,
     xlab = "OUT",
     main = paste("Histogram of the fuzzy set OUT scores"))

# Plot the raw data against the fuzzy set scores:
plot(DT$OUT_raw, DT$OUT,
     main = "Calibration of OUT" ,
     xlab = "Raw score" ,
     ylab = "Calibrated score",
     abline (h = 0.5 ,
             v = 0.2))

head(DT)

# To remove columns with raw data
DT <- DT[,-c(1:7)]
head(DT)

# Examine skewness of the data:
skew.check(DT)

DT <- round(DT, digits=2)
head(DT)

# Save calibrated data set as a csv file

write.csv(DT, "calibrated_fs.csv")


# Outcome: reappointment ----

rm(list=ls())

DT <- read.csv("calibrated_fs.csv", row.names = 1, sep=",")


head(DT)

# Analysis of necessity ----

QCAfit(DT[, 1:5], DT$OUT, names(DT[, 1:5]), necessity = TRUE)


# create XY plot for VOT

xy.plot("VOT", 
        "OUT", 
        data = DT,
        xlab="VOT", 
        ylab="OUT", 
        necessity=TRUE,
        jitter = TRUE) 

# VOT is a trivial necessary condition 


SUIN_y <- superSubset(data = DT, 
                      outcome = "OUT",
                      conditions = c("VOT", "STAB", "EFF", "POPUL", "ECON"),
                      relation = "necessity",
                      incl.cut = 0.90,
                      cov.cut = 0.6,
                      ron.cut = 0.5,
                      depth = 2)
SUIN_y

# no

# Analysis of sufficiency ----

# To create a truth table

TT <- truthTable(DT, outcome = "OUT",
                 conditions = colnames(DT[,1:5]),
                 incl.cut1 = .75,
                 complete = TRUE,
                 show.cases = TRUE,
                 PRI = TRUE,
                 sort.by = c("incl"))


TT

# 0.75 is a meaningful cut-off for consistency 


# Conservative solution 

sol_c <- minimize(TT, details = TRUE, 
                  show.cases = TRUE, 
                  use.tilde=FALSE)
sol_c


# XY-plot 

pimplot(data = DT,
        results = sol_c,
        outcome = "OUT",
        all_labels = TRUE,
        jitter = TRUE)

# Typical cases

typ_y <- smmr(results = sol_c,
              outcome = "OUT" ,
              sol = 1 ,
              match = FALSE,
              cases = 1,
              term = 1)

typ_y

# Deviant cases
dev_y <- smmr(results = sol_c,
              outcome = "OUT" ,
              sol = 1 ,
              match = FALSE,
              cases = 3,
              term = 1)

dev_y

# Most parsimonious solution 
sol_p <- minimize(TT, details = TRUE, 
                  include = "?", 
                  show.cases = TRUE)
                 
                  
sol_p

sol_p$SA


# Intermediate solution
sol_i <- minimize(TT, details = TRUE, include = "?",  
                  dir.exp = c(1,1,1,1,1),
                  show.cases = TRUE)

sol_i

sol_i$i.sol$C1P1$EC



# Outcome: dismissal ----

# Analysis of necessity ----

QCAfit(DT[, 1:5], DT$OUT, names(DT[, 1:5]), necessity = TRUE, neg.out = TRUE)

# No necessary conditions

SUIN_ny <- superSubset(data = DT, 
                       outcome = "~OUT",
                       conditions = c("VOT", "STAB", "EFF", "POPUL", "ECON"),
                       relation = "necessity",
                       incl.cut = 0.90,
                       cov.cut = 0.6,
                       ron.cut = 0.5,
                       depth = 2)

SUIN_ny

# No necessary disdjunctions

# Analysis of sufficiency ----

# To create a truth table

TT_n <- truthTable(DT, outcome = "OUT", neg.out = TRUE,
                   conditions = colnames(DT[,1:5]),
                   incl.cut1 = 0.75,
                   complete = TRUE,
                   show.cases = TRUE,
                   sort.by = c("incl"))


# 0.75 is a consistency threshold                
TT_n


sol_c_n <- minimize(TT_n, 
                    details = TRUE, 
                    show.cases = TRUE)



sol_c_n

# XY-plot 

pimplot(data = DT,
        results = sol_c_n,
        outcome = "~OUT",
        all_labels = TRUE,
        jitter = TRUE)

# Typical cases
typ_y_n <- smmr(results = sol_c_n,
                outcome = "~OUT" ,
                sol = 1 ,
                match = FALSE,
                cases = 1,
                term = 1)

typ_y_n

# Deviant cases
dev_y_n <- smmr(results = sol_c_n,
                outcome = "~OUT" ,
                sol = 1 ,
                match = FALSE,
                cases = 3,
                term = 1)

dev_y_n

# Parsimonious solution
sol_p_n <- minimize(TT_n, 
                    details = TRUE, 
                    include = "?", 
                    row.dom = TRUE, 
                    show.cases = TRUE,
                    exclude = c("16", "24", "28"))
                
# simplifying assumptions 16, 24, and 28 are excluded as they include 
# four conditions in their presence, this contradict the assumption that 
# conditions contribute to the outcome dismissal in their absence
                    
sol_p_n 
sol_p_n$SA


# Intermediate solution 
sol_i_n <- minimize(TT_n, details = TRUE, include = "?", 
                    show.cases = TRUE, 
                    dir.exp = c(0, 0, 0, 0, 0),
                    exclude = c("16", "24"))
                    
# rows 16 and 24 contradict directional expectations 
# stating that conditions contribute to the outcome in 
# their absence

sol_i_n
sol_i_n$i.sol$C1P1$EC


# Check for simultaneous subset relations
SSR<-intersect(rownames(TT$tt)[TT$tt$OUT==1],rownames(TT_n$tt)[TT_n$tt$OUT==1])
SSR
# none

# Check for any contradictory simplifying assumptions
CSA <- intersect(rownames(sol_p$i.sol$sol_p$C1P1$SA), rownames(sol_p_n$i.sol$C1P1$sol_p_n$SA))
CSA 
# none

# Check for any contradictory easy counterfactuals
CEC <- intersect(rownames(sol_i$i.sol$C1P1$EC), rownames(sol_i_n$i.sol$C1P1$EC))
CEC

# none

# Remove everything from the working environment:
rm(list=ls())


# Robustness Test 1: Crisp calibration ----

# Remove everything from the working environment:
rm(list=ls())


# Load raw data:

DT <- read.csv("raw_data.csv", row.names = 1, sep=",")
head(DT)



#VOT#


# Calibrate the result of the Duma elections
VOT <- calibrate(DT$VOT_raw_1,
                 type = "crisp",
                 thresholds = c(51))



VOT

# To add the new calibrated set to the data frame:
DT$VOT<-VOT
head(DT)


# STAB #

STAB <- ifelse(DT$STAB_raw <= 1.5, 1, 0)


STAB 

# To add the new calibrated set to the data frame:
DT$STAB<-STAB
head(DT)

# EFF #

EFF <- ifelse(DT$EFF_raw <= 40, 1, 0)


EFF

# To add the new calibrated set to the data frame:
DT$EFF <-EFF
head(DT)


# POPUL # 

POPUL <- calibrate(DT$POPUL_raw,
                   type = "crisp",
                   thresholds = c(40))

POPUL

# To add the new calibrated set to the data frame:
DT$POPUL<-POPUL
head(DT)


# ECON # 

ECON <- calibrate(DT$ECON_raw,
                 type = "crisp",
                 thresholds = c(2.2))

ECON

# To add the new calibrated set to the data frame:
DT$ECON<-ECON
head(DT)

# OUT # 

DT$OUT <- DT$OUT_raw
head(DT) 

# To remove columns with raw data
DT <- DT[,-c(1:7)]
head(DT)

# Examine skewness of the data:
skew.check(DT)


# Save calibrated data set as a csv file

write.csv(DT, "calibrated_cs.csv")


# Remove everything from the working environment:
rm(list=ls())


# Load raw data:

DT <- read.csv("calibrated_cs.csv", row.names = 1, sep=",")
head(DT)

# Analysis of necessity ----

QCAfit(DT[, 1:5], DT$OUT, names(DT[, 1:5]), necessity = TRUE)


# create XY plot for VOT

xy.plot("VOT", 
        "OUT", 
        data = DT,
        xlab="VOT", 
        ylab="OUT", 
        necessity=TRUE,
        jitter = TRUE) 

# VOT is a trivial necessary condition 


SUIN_y <- superSubset(data = DT, 
                      outcome = "OUT",
                      conditions = c("VOT", "STAB", "EFF", "POPUL", "ECON"),
                      relation = "necessity",
                      incl.cut = 0.90,
                      cov.cut = 0.6,
                      ron.cut = 0.5,
                      depth = 2)
SUIN_y

# no

# Analysis of sufficiency ----

# To create a truth table

TT <- truthTable(DT, outcome = "OUT",
                 conditions = colnames(DT[,1:5]),
                 incl.cut1 = .75,
                 complete = TRUE,
                 show.cases = TRUE,
                 PRI = TRUE,
                 sort.by = c("incl"))

TT

# 0.75 is a meaningful cut-off for consistency 


# Conservative solution 

sol_c <- minimize(TT, details = TRUE, 
                  show.cases = TRUE, 
                  use.tilde=FALSE)
sol_c


# XY-plot 

pimplot(data = DT,
        results = sol_c,
        outcome = "OUT",
        all_labels = TRUE,
        jitter = TRUE)

# Typical cases

typ_y <- smmr(results = sol_c,
              outcome = "OUT" ,
              sol = 1 ,
              match = FALSE,
              cases = 1,
              term = 1)

typ_y

# Deviant cases
dev_y <- smmr(results = sol_c,
              outcome = "OUT" ,
              sol = 1 ,
              match = FALSE,
              cases = 3,
              term = 1)

dev_y


# Outcome: dismissal ----

# Analysis of necessity ----

QCAfit(DT[, 1:5], DT$OUT, names(DT[, 1:5]), necessity = TRUE, neg.out = TRUE)

# No necessary conditions

SUIN_ny <- superSubset(data = DT, 
                       outcome = "~OUT",
                       conditions = c("VOT", "STAB", "EFF", "POPUL", "ECON"),
                       relation = "necessity",
                       incl.cut = 0.90,
                       cov.cut = 0.6,
                       ron.cut = 0.5,
                       depth = 2)

SUIN_ny

# No necessary disdjunctions

# Analysis of sufficiency ----

# To create a truth table

TT_n <- truthTable(DT, outcome = "OUT", neg.out = TRUE,
                   conditions = colnames(DT[,1:5]),
                   incl.cut1 = 0.75,
                   complete = TRUE,
                   show.cases = TRUE,
                   sort.by = c("incl"))


# 0.75 is a consistency threshold                
TT_n


sol_c_n <- minimize(TT_n, 
                    details = TRUE, 
                    show.cases = TRUE)



sol_c_n

# XY-plot 

pimplot(data = DT,
        results = sol_c_n,
        outcome = "~OUT",
        all_labels = TRUE,
        jitter = TRUE)

# Typical cases
typ_y_n <- smmr(results = sol_c_n,
                outcome = "~OUT" ,
                sol = 1 ,
                match = FALSE,
                cases = 1,
                term = 1)

typ_y_n

# Deviant cases
dev_y_n <- smmr(results = sol_c_n,
                outcome = "~OUT" ,
                sol = 1 ,
                match = FALSE,
                cases = 3,
                term = 1)

dev_y_n


# Check for simultaneous subset relations
SSR<-intersect(rownames(TT$tt)[TT$tt$OUT==1],rownames(TT_n$tt)[TT_n$tt$OUT==1])
SSR
# none


# Robustness test 2: Increasing consistency cut-off ----
# Outcome: reappointment ----

rm(list=ls())


DT <- read.csv("calibrated_fs.csv", row.names = 1, sep=",")

head(DT)

# Analysis of sufficiency ----

# To create a truth table

TT <- truthTable(DT, outcome = "OUT",
                 conditions = colnames(DT[,1:5]),
                 incl.cut1 = .80,
                 complete = TRUE,
                 show.cases = TRUE,
                 PRI = TRUE,
                 sort.by = c("OUT","incl", "n"))

TT

# 0.8 is a meaningful cut-off for consistency 


# Conservative solution 

sol_c <- minimize(TT, details = TRUE, 
                  show.cases = TRUE, 
                  use.tilde=FALSE)
sol_c

# XY-plot 

pimplot(data = DT,
        results = sol_c,
        outcome = "OUT",
        all_labels = TRUE,
        jitter = TRUE)



# Typical cases

typ_y <- smmr(results = sol_c,
              outcome = "OUT" ,
              sol = 1 ,
              match = FALSE,
              cases = 1,
              term = 1)

typ_y

# Deviant cases
dev_y <- smmr(results = sol_c,
              outcome = "OUT" ,
              sol = 1 ,
              match = FALSE,
              cases = 3,
              term = 1)

dev_y

# Outcome: dismissal ----

 
# Analysis of sufficiency ----

# To create a truth table

TT_n <- truthTable(DT, outcome = "OUT", neg.out = TRUE,
                   conditions = colnames(DT[,1:5]),
                   incl.cut1 = 0.80,
                   complete = TRUE,
                   show.cases = TRUE,
                   sort.by = c("OUT","incl", "n"))


# 0.80 is a consistency threshold                
TT_n


sol_c_n <- minimize(TT_n, 
                    details = TRUE, 
                    show.cases = TRUE)



sol_c_n

# XY-plot 

pimplot(data = DT,
        results = sol_c_n,
        outcome = "~OUT",
        all_labels = TRUE,
        jitter = TRUE)


# Typical cases
typ_y_n <- smmr(results = sol_c_n,
                outcome = "~OUT" ,
                sol = 1 ,
                match = FALSE,
                cases = 1,
                term = 1)

typ_y_n

# Deviant cases
dev_y_n <- smmr(results = sol_c_n,
                outcome = "~OUT" ,
                sol = 1 ,
                match = FALSE,
                cases = 3,
                term = 1)

dev_y_n


# Check for simultaneous subset relations
SSR<-intersect(rownames(TT$tt)[TT$tt$OUT==1],rownames(TT_n$tt)[TT_n$tt$OUT==1])
SSR
# none


# Robustness: sensitivity ranges of the calibration anchors ----


rm(list=ls())

#load the raw data
DT_raw <- read.csv("raw_data.csv", row.names = 1, sep=",")
head(DT_raw)

#load the calibrated data set
DT <- read.csv("calibrated_fs.csv", row.names = 1, sep=",") 
head(DT)

# Create the initial solution:

conds = names(DT[,1:5])
conds

IS <- minimize(data = DT,
               outcome  = "OUT",
               conditions = conds,
               incl.cut = 0.75,
               n.cut = 1,
               details = TRUE)


IS

# Sensitivity ranges:

# VOT_2007
rob.calibrange(
        raw.data = DT_raw,
        calib.data = DT,
        test.cond.raw = "VOT_raw_1",
        test.cond.calib = "VOT",
        test.thresholds = c(48, 51, 65),
        step = 2,
        max.runs = 40,
        outcome  = "OUT",
        conditions =  conds,
        incl.cut = 0.75,
        n.cut = 1,
)

# VOT_2011
rob.calibrange(
        raw.data = DT_raw,
        calib.data = DT,
        test.cond.raw = "VOT_raw_2",
        test.cond.calib = "VOT",
        test.thresholds = c(29, 40, 49),
        step = 2,
        max.runs = 40,
        outcome  = "OUT",
        conditions =  conds,
        incl.cut = 0.75,
        n.cut = 1,
)



# STAB
rob.calibrange(
        raw.data = DT_raw,
        calib.data = DT,
        test.cond.raw = "STAB_raw",
        test.cond.calib = "STAB",
        test.thresholds = c(2, 1.5, 1),
        step = 2,
        max.runs = 40,
        outcome  = "OUT",
        conditions =  conds,
        incl.cut = 0.75,
        n.cut = 1,
)

# EFF

rob.calibrange(
        raw.data = DT_raw,
        calib.data = DT,
        test.cond.raw = "EFF_raw",
        test.cond.calib = "EFF",
        test.thresholds = c(60, 40, 20),
        step = 2,
        max.runs = 40,
        outcome  = "OUT",
        conditions =  conds,
        incl.cut = 0.75,
        n.cut = 1,
)

# POPUL

rob.calibrange(
        raw.data = DT_raw,
        calib.data = DT,
        test.cond.raw = "POPUL_raw",
        test.cond.calib = "POPUL",
        test.thresholds = c(30, 40, 60),
        step = 2,
        max.runs = 40,
        outcome  = "OUT",
        conditions =  conds,
        incl.cut = 0.75,
        n.cut = 1,
)

# ECON


rob.calibrange(
        raw.data = DT_raw,
        calib.data = DT,
        test.cond.raw = "ECON_raw",
        test.cond.calib = "ECON",
        test.thresholds = c(0, 2.5, 4),
        step = 2,
        max.runs = 40,
        outcome  = "OUT",
        conditions =  conds,
        incl.cut = 0.75,
        n.cut = 1,
)



